package com.sunxd.zstudy.designPattern.support.observer;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @author: sun.xd
 * @date: 2021-10-18 13:58
 **/
@Configuration
public class EventConfig implements ApplicationContextAware {

    private Map<String, List<EventListener>> map = Maps.newHashMap();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, EventListener> beansOfType = applicationContext.getBeansOfType(EventListener.class);
        beansOfType.forEach((k, v) -> {
            String typeName = null;
            Type[] genericInterfaces = applicationContext.getBean(k, EventListener.class).getClass().getGenericInterfaces();
            Type type = genericInterfaces[0];
            if (type instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) type;
                typeName = parameterizedType.getActualTypeArguments()[0].getTypeName();
            }
            if(StringUtils.isEmpty(typeName)){
                return;
            }
            if (map.containsKey(typeName)) {
                map.get(typeName).add(v);
            } else {
                map.put(typeName, Lists.newArrayList(v));
            }
        });
    }

            ExecutorService executorService = new ThreadPoolExecutor(4, 20,
                60, TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(100000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());

    public void execute(String key,EventOb eventOb){
        if(map.containsKey(key)){
            CompletableFuture.runAsync(()->{map.get(key).forEach(x -> x.wakeUp(eventOb));},executorService);
//            map.get(key).forEach(x -> x.wakeUp(eventOb));
        }
    }
}
